from functools import reduce
import redis
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from rest_framework.generics import ListAPIView
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from rest_framework_jwt.utils import jwt_decode_handler

from .models import Carousel, Category, Goods, GoodCollect
from .serializers import CarouselSer, GoodsSer, CateSer, GoodImgSer, GoodCollectSer
from users.models import User


class CarouselView(ListAPIView):
    queryset = Carousel.objects.all()
    serializer_class = CarouselSer


class GoodsByCateName(APIView):
    def post(self, request):
        """
        根据类别名获取商品数据
        """
        name = request.data.get('categoryName')
        # 获取类别信息
        cate = Category.objects.get(cate_name=name)
        # 根据类别获取商品
        goods = cate.goods_set.all()
        # 使用序列化器输出
        good_ser = GoodsSer(goods, many=True)
        return Response(good_ser.data)


class HotProductViews(APIView):
    def post(self, request):
        """:param: ["电视机", "空调", "洗衣机"],1. 获取前端传递来的参数:["电视机", "空调", "洗衣机"]"""
        # 前端传来的类别信息
        cate_names = request.data.get('categoryName')
        cates = [Category.objects.get(cate_name=name) for name in cate_names]
        goods = [cate.goods_set.all() for cate in cates]

        # 根据商品销量对商品进行排序
        # map 和reduce 都是把可迭代对象的元素放在func中进行操作,但是返回的结果不一样
        # reduce:(func, iterable)---> 返回的是值
        # map:(func, iterable) ---> 返回的是新的迭代对象[]
        # reduce(lambda x,y: x | y, goods) 会拿到所有商品放在一起的一个列表
        # order_by()默认是升序排列, 我们要降序排列,前面加-
        res = reduce(lambda x, y: x | y, goods).order_by('-count')
        # 对返回的结果进行序列化输出
        ser = GoodsSer(res, many=True)
        return Response(ser.data)


# 1. 获取所有的商品类别
class CategoryView(APIView):
    def post(self, request):
        cates = Category.objects.all()
        ser = CateSer(cates, many=True)
        return Response(ser.data)


# 2. 根据类别id获取此类别下所有的商品
class GoodsByCategoryId(APIView):

    def get(self, request):
        # 1. 获取到前端传递来的商品类别
        # cate_id = request.data.get('categoryID')[0]
        # TODO 查询字符串传参
        cate_id = request.query_params['categoryID']
        try:
            cate = Category.objects.get(id=cate_id)
        except Exception as e:
            return Response({'msg': "没有此类别"})
        # 根据类别获取所有的商品
        goods = cate.goods_set.all()
        good_ser = GoodsSer(goods, many=True)
        return Response(good_ser.data)


# 3. 获取所有的商品
class GoodsView(APIView):
    def post(self, request):
        good = Goods.objects.all()
        ser = GoodsSer(good, many=True)
        return Response(ser.data)


class MyPagenations(PageNumberPagination):
    # 分页时前端查询的关键字
    page_size_query_param = "pageSize"
    page_query_param = "page"
    page_size = 7


# 3. 获取所有的商品
class GoodsViews(ListAPIView):
    queryset = Goods.objects.all()
    serializer_class = GoodsSer
    # 分页器
    # 指定分页器:
    # 有2种配置方式:
    # 1. 在settings的全局配置
    # 2. 在指定类视图下配置,只对当前的类视图分页
    pagination_class = MyPagenations


class GoodPicture(APIView):
    def get(self, request):
        # 获取商品id: 查询字符串传参，query_params
        gid = request.query_params.get('gid')
        if gid:
            try:
                good = Goods.objects.get(id=gid)
            except Exception as e:
                return Response({'msg': "没有商品", "code": 400})
            # 根据商品获取商品图片
            imgs = good.goodimg_set.all()
            # 对商品图片进行序列化输出
            ser = GoodImgSer(imgs, many=True)
            return Response({'msg': "ok", "code": 200, 'imgs': ser.data})
        else:
            return Response({'msg': '商品错误', "code": 400})


class GoodDetail(APIView):
    def get(self, request):
        # 获取商品id: 查询字符串传参, query_params
        gid = request.query_params.get('gid')
        if gid:
            # 根据商品id 获取商品,然后再根据商品获取商品图片
            try:
                good = Goods.objects.get(id=gid)
            except Exception as e:
                return Response({"msg": "没有此商品", "code": 400})
            ser = GoodsSer(good)
            return Response(ser.data)
        else:
            # gid 获取失败
            return Response({'msg': "商品id 获取错误", "code": 400})


# 添加历史浏览记录
"""
前端传递的参数是:gid, token

后端:
1. 获取前端传来的gid 和 token
2. 判断gid的商品是否存在
3. 判断token, 判断用户是否登录, 没有的话就登录
4. 判断没问题的把用户信息和商品信息写入redis,list : key(user.id)/v(商品)
5. 添加完成,返回
"""


class AddHistory(APIView):
    def post(self, request):
        # 获取前端传来的gid 和 token
        gid = request.data.get('productID')
        token = request.data.get('token')
        # 判断
        if not token:
            # 此时没有token,shuoming 没有登录
            return Response({'msg': "请先登录!", "code": 400})
        else:
            # 登录过的,需要校验token
            # decode:解码,
            payload = jwt_decode_handler(token)
            # 在payload 中获取登录的用户信息
            user_id = payload.get('user_id')
            # 把用户信息和商品id写入redis
            redis_cli = redis.Redis(host="localhost", port=6379, password=123)
            # 写入redis: list   history_userid: gid
            history = "history_%s" % user_id
            # 直接添加
            # 若存在此商品直接删除
            redis_cli.lrem(history, 0, gid)
            # 删除后载添加
            redis_cli.lpush(history, gid)
            redis_cli.close()

            return Response({'msg': "添加历史浏览记录成功", "code": 200})


class CollectViews(APIView):
    def post(self, request):
        """
        添加收藏
        思路分析:
        1. 获取前端传来的用户以及商品id
        2. 写入数据库: goodscollect
        3. 添加收藏,必须先登录
        """
        dict_user = request.data.get('user')
        print("user>>>>", dict_user)
        gid = request.data.get('product_id')
        # 判断商品是否存在
        if not dict_user:
            return Response({'msg': "获取用户信息错误", "code": 400})
        if not gid:
            return Response({"msg": "商品错误", "code": 400})
        try:
            user = User.objects.get(username=dict_user['userName'])
        except Exception as e:
            return Response({'msg': "没有此用户", "code": 400})
        try:
            good = Goods.objects.get(id=gid)
        except Exception as e:
            return Response({'msg': "没有此商品", "code": 400})
        # 有商品和用户,写入户数据库
        good = GoodCollect.objects.create(user=user, goods=good)
        ser = GoodCollectSer(good)
        return Response({"code": 200, "data": ser.data, "msg": "添加收藏成功"})


class CollectInfoView(APIView):
    """获取收藏的商品"""
    def post(self, request):
        """
        思路分析:
        1. 获取前端传来的用户信息
        2. 根据用户信息在收藏表查询收藏的商品
        """
        dict_user = request.data.get("user")
        token = request.data.get('token')
        # print("user>>>",dict_user)
        # 做判断, 判断当前的用户是否在登录的表中
        # 只要有一个为空说明前端传来的数据没有获取到, 此时让用户登录
        if not all([dict_user, token]):
            return Response({"msg": "请先登录", "code": 400})
        # 判断传来的用户信息和token 中的用户信息是否一致,若一致,才能获取收藏的商品
        try:
            user = User.objects.get(username=dict_user['userName'])
        except Exception as e:
            return Response({'msg': "没有此用户", "code": 400})
        # 校验token
        payload = jwt_decode_handler(token)
        print("payload>>>", payload)
        user_id = payload.get('user_id')
        # 校验传来的用户user和token中的user是一个,不一个说明用户信息被盗取(篡改),不让登录
        if user_id == user.id:
            # 此时说明登录的用户和传递来的用户一致,才能获取收藏的商品
            products = user.goodcollect_set.all()
            print("product---->", products)
            collect_goods = []  # 搜藏的商品信息
            for product in products:
                collect_goods.append({
                    "id": product.goods.id,
                    'sku_name': product.goods.sku_name,
                    "price": product.goods.price,
                    "selling_price": product.goods.selling_price,
                    "img": product.goods.img,
                    "title": product.goods.title,
                    "instruction": product.goods.instruction
                })
            return Response({'msg': "ok", "data": collect_goods, "code": 200})
        else:
            return Response({'msg': "用户信息错误, 请先登录", "code": 400})


class CollectDelView(APIView):
    """
    删除指定收藏的商品
    """
    def delete(self, request):
        """
        获取前端传来的user 和商品id
        """
        dict_user = request.data.get("user")
        print("user>>>", dict_user)
        try:
            user = User.objects.get(username=dict_user['userName'])
        except Exception as e:
            return Response({'msg': "没有此用户", "code": 400})
        pid = request.data.get('product_id')
        # 删除指定的商品
        GoodCollect.objects.filter(user_id=user.id, goods_id=pid).delete()
        return Response({'msg': "删除成功", "code": 200})
